﻿using RWSBeeldbank.Common;
using RWSBeeldbank.Utility;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Net.Http;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading;
using System.Threading.Tasks;
using Windows.ApplicationModel;
using Windows.ApplicationModel.Resources;
using Windows.ApplicationModel.Resources.Core;
using Windows.Data.Json;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.Storage;
using Windows.Storage.Streams;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Imaging;

// The data model defined by this file serves as a representative example of a strongly-typed
// model that supports notification when members are added, removed, or modified.  The property
// names chosen coincide with data bindings in the standard item templates.
//
// Applications may use this model as a starting point and build on it, or discard it entirely and
// replace it with something appropriate to their needs.

namespace RWSBeeldbank.Data
{
    /// <summary>
    /// Base class for <see cref="MediaObjectDataItem"/> and <see cref="MediaObjectDataGroup"/> that
    /// defines properties common to both.
    /// </summary>
    [Windows.Foundation.Metadata.WebHostHidden]
    public abstract class MediaObjectDataCommon : RWSBeeldbank.Common.BindableBase
    {
        internal static Uri _baseUri = new Uri("ms-appx:///");

        public MediaObjectDataCommon(String uniqueId, String title, String _largeImagePath)
        {
            this._uniqueId = uniqueId;
            this._title = title;
            this._largeImagePath = _largeImagePath;
        }

        private string _uniqueId = string.Empty;
        public string UniqueId
        {
            get { return this._uniqueId; }
            set { this.SetProperty(ref this._uniqueId, value); }
        }

        private string _title = string.Empty;
        public string Title
        {
            get { return this._title; }
            set { this.SetProperty(ref this._title, value); }
        }

        private ImageSource _largeImage = null;
        private String _largeImagePath = null;

        public Uri LargeImagePath
        {
            get
            {
                return new Uri(MediaObjectDataCommon._baseUri, this._largeImagePath);
            }
        }

        public ImageSource LargeImage
        {
            get
            {
                if (this._largeImage == null && this._largeImagePath != null)
                {
                    this._largeImage = new BitmapImage(new Uri(MediaObjectDataCommon._baseUri, this._largeImagePath));
                }
                return this._largeImage;
            }

            set
            {
                this._largeImagePath = null;
                this.SetProperty(ref this._largeImage, value);
            }
        }

        public void SetLargeImage(String path)
        {
            // path = http://beeldbank.rws.nl/MediaService/313367
            //
            // must result in
            //
            // _largeImagePath = http://beeldbank.rws.nl/MediaService/[313367] to get the full source image
            //
            this._largeImage = null;

            this._largeImagePath = path.Replace(Constants.HTTP, Constants.HTTPS).Replace(Constants.TILE_WIDTH_SOURCE, Constants.LARGE_WIDTH_TARGET) + Constants.TILE_WIDTH_TARGET2;
            
            this.OnPropertyChanged("LargeImage");
        }

        public void SetLargeImageFromId(String id)
        {
            this._largeImage = null;
            this._largeImagePath = "https://beeldbank.rws.nl/Home/DisplayDetail/" + id;
            this.OnPropertyChanged("LargeImage");
        }

        public string GetLargeImageUri()
        {
            return _largeImagePath;
        }
    }

    /// <summary>
    /// MediaObject item data model.
    /// </summary>
    public class MediaObjectDataItem : MediaObjectDataCommon
    {
        public MediaObjectDataItem()
            : base(String.Empty, String.Empty, String.Empty)
        {
        }

        public MediaObjectDataItem(String uniqueId, String title, String altTitle, Uri LargeImagePath, Uri TileImagePath, int filenumber)
            : base(uniqueId, title, LargeImagePath.ToString())
        {
            this._filenumber = filenumber;
            this._altTitle = altTitle;
            this._tileImagePath = TileImagePath.ToString();
            this.DirectLink = Constants.DIRECTLINKBASE + this.Id.ToString();
        }

        public MediaObjectDataItem(String uniqueId, String title, String altTitle, String imagePath, int filenumber, String description, MediaObjectDataGroup group)
            : base(uniqueId, title, imagePath)
        {
            this._filenumber = filenumber;
            this._description = description;
            this._group = group;
            this._altTitle = altTitle;
        }

        private string _altTitle = string.Empty;
        public string AltTitle
        {
            get { return this._altTitle; }
            set { this.SetProperty(ref this._altTitle, value); }
        }

        private string _author = string.Empty;
        public string Author
        {
            get { return this._author; }
            set
            {
                this.SetProperty(ref this._author, value);
                if (this.Author.Trim() != "")
                    this.CopyRight = Constants.COPYRIGHTBASE + " / " + this.Author;
            }
        }

        private string _copyright = Constants.COPYRIGHTBASE;
        public string CopyRight
        {
            get { return this._copyright; }
            set { this.SetProperty(ref this._copyright, value); }
        }

        private string _dateCreated = string.Empty;
        public string DateCreated
        {
            get { return this._dateCreated; }
            set
            {
                if (value != "1-1-1900")
                    this.SetProperty(ref this._dateCreated, value);
                else
                {
                    var resourceLoader = new ResourceLoader();

                    this.SetProperty(ref this._dateCreated, resourceLoader.GetString("DateCreatedUnknown"));
                }
            }
        }

        private string _description = string.Empty;
        public string Description
        {
            get { return this._description; }
            set { this.SetProperty(ref this._description, value); }
        }

        private string _directLink = string.Empty;
        public string DirectLink
        {
            get { return this._directLink; }
            set { this.SetProperty(ref this._directLink, value); }
        }

        private int _filenumber = 0;
        public int FileNumber
        {
            get { return this._filenumber; }
            set
            {
                this.SetProperty(ref this._filenumber, value);
            }
        }

        private int _googlezoom = 8;
        public int GoogleZoom
        {
            get { return this._googlezoom; }
            set
            { 
                if (value > 0)
                    this.SetProperty(ref this._googlezoom, value); 
            }
        }

        private string _gps = string.Empty;
        public string GPS
        {
            get { return this._gps; }
            set { this.SetProperty(ref this._gps, value); }
        }

        private MediaObjectDataGroup _group;
        public MediaObjectDataGroup Group
        {
            get { return this._group; }
            set { this.SetProperty(ref this._group, value); }
        }

        private int _height = 0;
        public int Height
        {
            get { return this._height; }
            set { this.SetProperty(ref this._height, value); }
        }

        private int _id = 0;
        public int Id
        {
            get { return this._id; }
            set
            {
                this.SetProperty(ref this._id, value);
            }
        }

        private string _inventoryId = string.Empty;
        public string InventoryId
        {
            get { return this._inventoryId; }
            set { this.SetProperty(ref this._inventoryId, value); }
        }

        private string _keywords = string.Empty;
        public string Keywords
        {
            get { return this._keywords; }
            set { this.SetProperty(ref this._keywords, value); }
        }

        private double _latitude = Double.NaN;
        public double Latitude
        {
            get { return this._latitude; }
            set { this.SetProperty(ref this._latitude, value); }
        }

        private string _location = string.Empty;
        public string Location
        {
            get { return this._location; }
            set { this.SetProperty(ref this._location, value); }
        }

        private double _longitude = Double.NaN;
        public double Longitude
        {
            get { return this._longitude; }
            set { this.SetProperty(ref this._longitude, value); }
        }

        private string _province = string.Empty;
        public string Province
        {
            get { return this._province; }
            set { this.SetProperty(ref this._province, value); }
        }

        private string _themes = string.Empty;
        public string Themes
        {
            get { return this._themes; }
            set { this.SetProperty(ref this._themes, value); }
        }


        private string _rating = string.Empty;
        public string Rating 
        {
            get { return this._rating; }
            set { this.SetProperty(ref this._rating, value); }
        }


        private int _typeid = 0;
        public int TypeId
        {
            get { return this._typeid; }
            set { this.SetProperty(ref this._typeid, value); }
        }

        public string VideoFile
        {
            get { return Constants.WEBSITEBASE + Constants.VIDEO_URL + (FileNumber / 150).ToString() + "/" + FileNumber.ToString() + Constants.VIDEO_EXTENSION; }
        }

        private string _videoFormat = string.Empty;
        public string VideoFormat
        {
            get { return this._videoFormat; }
            set { this.SetProperty(ref this._videoFormat, value); }
        }

        private string _videoLength = string.Empty;
        public string VideoLength
        {
            get { return this._videoLength; }
            set { this.SetProperty(ref this._videoLength, value); }
        }

        private ImageSource _tileImage;
        private string _tileImagePath;

        public Uri TileImagePath
        {
            get { return new Uri(MediaObjectDataCommon._baseUri, this._tileImagePath); }
        }

        public ImageSource TileImage
        {
            get
            {
                if (this._tileImage == null && this._tileImagePath != null)
                {
                    this._tileImage = new BitmapImage(new Uri(MediaObjectDataCommon._baseUri, this._tileImagePath));
                }
                return this._tileImage;
            }
            set
            {
                this._tileImagePath = null;
                this.SetProperty(ref this._tileImage, value);
            }
        }

        public void SetTileImage(String path, String typePath)
        {
            // path = http://beeldbank.rws.nl/MediaService/313367
            //
            // must result in
            //
            // _tileImagePath = http://beeldbank.rws.nl/MediaService/[250x250-313367] to get a smaller image of the right size
            //
            // Or we can use the preview file, which is 600 pixels wide
            // That would lead to something like this 
            // this._tileImagePath = "https://beeldbank.rws.nl/Photos/" + (_filenumber/150).ToString() + "/" + _filenumber.ToString() + "s.jpg";
            //
            // Original version to generate the tile image using the MediaService
            // this._tileImagePath = path.Replace(Constants.HTTP, Constants.HTTPS).Replace(Constants.TILE_WIDTH_SOURCE, Constants.TILE_WIDTH_TARGET1) + Constants.TILE_WIDTH_TARGET2;

            this._tileImage = null;

            this._tileImagePath = typePath + (_filenumber / 150).ToString() + "/" + _filenumber.ToString() + "_[250x250].jpg";
            
            this.OnPropertyChanged("TileImage");
        }

        public void SetTileImageFromId(String id)
        {
            this._tileImage = null;
            this._tileImagePath = "https://beeldbank.rws.nl/Home/DisplayThumb/" + id;
            this.OnPropertyChanged("TileImage");
        }
    }

    /// <summary>
    /// MediaObject group data model.
    /// </summary>
    public class MediaObjectDataGroup : MediaObjectDataCommon
    {
        public MediaObjectDataGroup()
            : base(String.Empty, String.Empty, String.Empty)
        {
        }

        public MediaObjectDataGroup(String uniqueId, String title, String themeImagePath, String description, int mediaObjectsCount)
            : base(uniqueId, title, themeImagePath)
        {
            this.UniqueId = uniqueId;
            this.Title = title;
            this.SetGroupImage(themeImagePath);
            this.Description = description;
            this.MediaObjectsCount = mediaObjectsCount;
        }

        private ObservableCollection<MediaObjectDataItem> _items = new ObservableCollection<MediaObjectDataItem>();
        public ObservableCollection<MediaObjectDataItem> Items
        {
            get { return this._items; }
        }

        public IEnumerable<MediaObjectDataItem> TopItems
        {
            // Provides a subset of the full items collection to bind to from a GroupedItemsPage
            // for two reasons: GridView will not virtualize large items collections, and it
            // improves the user experience when browsing through groups with large numbers of
            // items.
            //
            // A maximum of 12 items are displayed because it results in filled grid columns
            // whether there are 1, 2, 3, 4, or 6 rows displayed
            get { return this._items.Take(6); }
        }

        private string _description = string.Empty;
        public string Description
        {
            get { return this._description; }
            set { this.SetProperty(ref this._description, value); }
        }

        private ImageSource _groupImage;
        private string _groupImagePath;

        public ImageSource GroupImage
        {
            get
            {
                if (this._groupImage == null && this._groupImagePath != null)
                {
                    this._groupImage = new BitmapImage(new Uri(MediaObjectDataCommon._baseUri, this._groupImagePath));
                }
                return this._groupImage;
            }
            set
            {
                this._groupImagePath = null;
                this.SetProperty(ref this._groupImage, value);
            }
        }

        public int MediaObjectsCount { get; set; }

        public void SetGroupImage(String path)
        {
            this._groupImage = null;
            this._groupImagePath = path;
            this.OnPropertyChanged("GroupImage");
        }
    }

    public class DynamicLoadItems : ObservableCollection<MediaObjectDataItem>, ISupportIncrementalLoading
    {
        private int _currentPage = 0; //page tracking
        private int _collectionId = 0;

        #region ISupportIncrementalLoading Members
        public bool HasMoreItems
        {
            get { return (this.Count <= Constants.MAX_NR_ITEMS); }
        }

        public Windows.Foundation.IAsyncOperation<LoadMoreItemsResult> LoadMoreItemsAsync(uint count)
        {
            return AsyncInfo.Run((ct) => LoadMoreItemsAsync(ct, count));
        }
        #endregion

        public void setGroupId(int collectionId)
        {
            _collectionId = collectionId;
        }

        public void resetCurrentPage()
        {
            _currentPage = 0;
        }
        
        private async Task<LoadMoreItemsResult> LoadMoreItemsAsync(CancellationToken ct, uint count)
        {
            uint moreItems = await LoadMoreItems(count);
            return new LoadMoreItemsResult() { Count = moreItems };
        }

        private async Task<uint> LoadMoreItems(uint count)
        {
            var items = await MediaObjectDataSource.GetTitles(Constants.PAGE_SIZE, _currentPage * Constants.PAGE_SIZE, _collectionId);

            this.Clear();

            foreach (var item in items)
            {
                this.Add(item);

                // add the right group to the item
                item.Group = MediaObjectDataSource._mediaObjectDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(_collectionId.ToString()));
            }

            _currentPage++;

            return (uint)items.Count();
        }
    }

    /// <summary>
    /// Creates a collection of groups and items.
    /// </summary>
    public sealed class MediaObjectDataSource
    {
        public static MediaObjectDataSource _mediaObjectDataSource = new MediaObjectDataSource();

        // DynamicLoadItems is a subset if items that is filled while scrolling. This collection is never bigger than 20 items   
        private DynamicLoadItems _dynamicLoadItems = new DynamicLoadItems();
                
        private static List<string> _allKeyWordsList = new List<string>();
        public static string[] AllKeywords
        {
            get { return _allKeyWordsList.ToArray(); }
        }

        private ObservableCollection<MediaObjectDataGroup> _allGroups = new ObservableCollection<MediaObjectDataGroup>();
        public ObservableCollection<MediaObjectDataGroup> AllGroups
        {
            get { return this._allGroups; }
            set { this._allGroups = AllGroups;  }
        }

        public DynamicLoadItems DynamicLoadItems(int collectionId)
        {
            _dynamicLoadItems.Clear();

            this._dynamicLoadItems.resetCurrentPage();
            this._dynamicLoadItems.setGroupId(collectionId);
            return this._dynamicLoadItems;
        }

        // Clear memory in order to be able to reload the app with a new value for TypeId
        public static void Clear()
        {
            _mediaObjectDataSource = new MediaObjectDataSource();
        }

        public static async Task<ObservableCollection<MediaObjectDataItem>> GetTitles(int numResults, int page, int collectionId)
        {
            // Retrieve mediaObject data from Beeldbank webserver
            //var client = new HttpClient();
            //client.MaxResponseContentBufferSize = Constants.MAX_RESPONSE_BUFFERSIZE;

            // Determine Media Type Id
            int typeId = Constants.ITEM_TYPE_DIGITAL;
            if (ApplicationData.Current.RoamingSettings.Values.ContainsKey("MediaType"))
                typeId = Convert.ToInt16(ApplicationData.Current.RoamingSettings.Values["MediaType"]);
            
            // load items for this theme from URL
            //var itemResponse = await client.GetAsync(new Uri(Constants.FEEDBASE + "/api/W8_ThemeMediaList?collectionId=" + collectionId + "&typeId="+ typeId + "&aantalResultaten=" + numResults + "&orderBy=7&skip=" + page));
            //var itemResult = await itemResponse.Content.ReadAsStringAsync();

            // Parse the JSON mediaObject data
            //var JsonItem = JsonArray.Parse(itemResult);

            var JsonItem = await Utility.Tools.cachedFeed(new Uri(Constants.FEEDBASE + "/api/W8_ThemeMediaList?collectionId=" + collectionId + "&typeId=" + typeId + "&aantalResultaten=" + numResults + "&orderBy=7&skip=" + page));



            CreateThemeItems(JsonItem, typeId);

            // Append the items of the specific group to the loading gridview
            return _mediaObjectDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(collectionId.ToString())).Items;
        }

        public static IEnumerable<MediaObjectDataGroup> GetGroups(string uniqueId)
        {
            if (!uniqueId.Equals("AllGroups")) throw new ArgumentException("Only 'AllGroups' is supported as a collection of groups");

            return _mediaObjectDataSource.AllGroups;
        }

        public static MediaObjectDataGroup GetGroup(string uniqueId)
        {
            // Simple linear search is acceptable for small data sets
            var matches = _mediaObjectDataSource.AllGroups.Where(group => group.UniqueId.Equals(uniqueId));
            if (matches.Count() == 1) return matches.First();
            return null;
        }

        public static MediaObjectDataItem GetItem(string uniqueId)   
        {
            string groupId = Tools.GetGroupId(uniqueId);

            if (groupId == null)
            {
                var matches = _mediaObjectDataSource.AllGroups.SelectMany(group => group.Items);
                var item = from b in matches
                           where b.Group.UniqueId == groupId
                           &&
                           b.UniqueId == uniqueId
                           select b;

                return item.FirstOrDefault();

            }
            else
            {
                // Simple linear search is acceptable for small data sets
                return _mediaObjectDataSource.AllGroups.SelectMany(group => group.Items).Where(item => item.UniqueId.Equals(uniqueId)).FirstOrDefault();
            }

        }

        public static async Task LoadMoreItemsAsync(int collectionId, int currentItemIndex)
        {
            var items = await MediaObjectDataSource.GetTitles(Constants.FLIPVIEW_PAGE_SIZE, currentItemIndex, collectionId);

            foreach (var item in items)
            {
                item.Group = MediaObjectDataSource._mediaObjectDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(collectionId.ToString()));
                _mediaObjectDataSource._dynamicLoadItems.Add(item);
            }         
        }

        public static async Task LoadRemoteDataAsync()
        {
            await LoadRemoteDataAsync("");
        }

        public static async Task LoadRemoteDataAsync(String searchString)
        {
            // Retrieve mediaObject data from Beeldbank webserver
            //var client = new HttpClient();
            //client.MaxResponseContentBufferSize = Constants.MAX_RESPONSE_BUFFERSIZE;

            // Determine Media Type Id
            int typeId = Constants.ITEM_TYPE_DIGITAL;
            if (ApplicationData.Current.RoamingSettings.Values.ContainsKey("MediaType"))
                typeId = Convert.ToInt16(ApplicationData.Current.RoamingSettings.Values["MediaType"]);

            //
            // check if requested content is already in local storage
            //
            //var localFolder = Windows.Storage.ApplicationData.Current.LocalFolder;
            //var mediaObjects = new JsonArray();
            //String filename = "cache\\topMediaList_" + typeId + ".txt";

            var mediaObjects = await Utility.Tools.cachedFeed(new Uri(Constants.FEEDBASE + "/api/W8_TopMediaList?searchString=" + searchString + "&typeId=" + typeId + "&aantalResultaten=6"));

            ////
            //// if there is a search string or the cache file does not extist or is expired
            ////
            //if (!searchString.Equals("") || (await Utility.Tools.DoesFileExistAsync(filename) == false || await Utility.Tools.IsFileExpiredAsync(filename, 60) == true))
            //{
            //    //
            //    // get the content form the URL
            //    //
            //    var response = await client.GetAsync(new Uri("https://beeldbank.rws.nl/api/W8_TopMediaList?searchString=" + searchString + "&typeId=" + typeId + "&aantalResultaten=6"));
            //    var result = await response.Content.ReadAsStringAsync();
            //    // Parse the JSON mediaObject data
            //    mediaObjects = JsonArray.Parse(result);

            //    // Write json result to the file
            //    StorageFile topMediaListFile = await localFolder.CreateFileAsync(filename, CreationCollisionOption.ReplaceExisting);
            //    await FileIO.WriteTextAsync(topMediaListFile, result);
            //}
            //else
            //{
            //    //
            //    // get the content form the cache file
            //    //
            //    StorageFile topMediaListFile = await localFolder.GetFileAsync(filename);
            //    var result = await FileIO.ReadTextAsync(topMediaListFile);
            //    mediaObjects = JsonArray.Parse(result);
            //}

            var groupThemes = await Utility.Tools.cachedFeed(new Uri(Constants.FEEDBASE + "/api/W8_ThemesList?typeId=" + typeId));



            //var groupResponse = await client.GetAsync(new Uri("https://beeldbank.rws.nl/api/W8_ThemesList?typeId=" + typeId));
            //var groupResult = await groupResponse.Content.ReadAsStringAsync();
            //// Parse the JSON group data
            //var groupThemes = JsonArray.Parse(groupResult);


            //// Write json result to the file
            //StorageFile topThemesList = await localFolder.CreateFileAsync("cache\\topThemesList.txt", CreationCollisionOption.ReplaceExisting);
            //await FileIO.WriteTextAsync(topThemesList, groupResult);



            if (typeId == Constants.ITEM_TYPE_DIGITAL)
            {
                var newMediaThemes = await Utility.Tools.cachedFeed(new Uri(Constants.FEEDBASE + "/api/W8_NewMediaList"));

                //var newMediaResponse = await client.GetAsync(new Uri("https://beeldbank.rws.nl/api/W8_NewMediaList"));
                //var newMediaResult = await newMediaResponse.Content.ReadAsStringAsync();
                //// Parse the JSON group data
                //var newMediaThemes = JsonArray.Parse(newMediaResult);


                //// Write json result to the file
                //StorageFile newMediaList = await localFolder.CreateFileAsync("cache\\newMediaList.txt", CreationCollisionOption.ReplaceExisting);
                //await FileIO.WriteTextAsync(newMediaList, newMediaResult);



                // Convert the JSON objects into MediaObjectDataItems and MediaObjectDataGroups
                CreateMediaObjectsAndMediaObjectGroups(mediaObjects, groupThemes, newMediaThemes, typeId);
            }
            else
            {
                // Convert the JSON objects into MediaObjectDataItems and MediaObjectDataGroups
                CreateMediaObjectsAndMediaObjectGroups(mediaObjects, groupThemes, typeId);
            }
        }

        public static async Task LoadLocalDataAsync()
        {
            // Retrieve mediaObject data from MediaObjects.txt
            var file = await Package.Current.InstalledLocation.GetFileAsync("Data\\RijkswaterstaatFull.txt"); // Data\\MediaObjects.txt
            var result = await FileIO.ReadTextAsync(file, UnicodeEncoding.Utf8);

            // Parse the JSON mediaObject data
            var mediaObjects = JsonArray.Parse(result);

            // Retrieve mediaObject data from MediaObjects.txt
            var groupFile = await Package.Current.InstalledLocation.GetFileAsync("Data\\ThemesList.txt"); // Data\\MediaObjects.txt
            var groupResult = await FileIO.ReadTextAsync(groupFile, UnicodeEncoding.Utf8);

            // Parse the JSON mediaObject data
            var groupThemes = JsonArray.Parse(groupResult);

            // Convert the JSON objects into MediaObjectDataItems and MediaObjectDataGroups and set the typeId to be of digital images
            CreateMediaObjectsAndMediaObjectGroups(mediaObjects, groupThemes, null, 19);
        }

        // Add item keywords to Suggestion List
        private static void AddKeywordsToSuggestionList(string keywordsString)
        {
            String[] keywords = keywordsString.Split('|');

            foreach (string x in keywords)
            {
                if (!_allKeyWordsList.Exists(p => p == x.Trim().ToLower()))
                {
                    _allKeyWordsList.Add(x.Trim().ToLower());
                }
            }
        }

        public static async Task SetRatingAsync(int mediaObjectId, int rating)
        {
            

            // Retrieve mediaObject data from Beeldbank webserver
            var client = new HttpClient();
            client.MaxResponseContentBufferSize = Constants.MAX_RESPONSE_BUFFERSIZE;
                        
            var response = await client.GetAsync(new Uri(Constants.FEEDBASE + "/api/W8_RateMediaObject?rating=" + rating + "&mediaObjectId=" + mediaObjectId));
            
            
            var result = await response.Content.ReadAsStringAsync();

            Tools.markItemAsRated(mediaObjectId, Convert.ToInt32(rating));
        }
        
        // AB: TODO check if this and the CreateMediaObjectsAndMediaObjectGroups(JsonArray array, JsonArray groupsArray) can be combined
        private static void CreateThemeItems(JsonArray array, int typeId)
        {
            foreach (var item in array)
            {
                var obj = item.GetObject();
                MediaObjectDataItem mediaObject = new MediaObjectDataItem();

                foreach (var key in obj.Keys)
                {
                    IJsonValue val;
                    if (!obj.TryGetValue(key, out val))
                        continue;

                    if (val.ValueType == JsonValueType.Null)
                        continue;

                    switch (key)
                    {
                        case "alttitle":
                            mediaObject.AltTitle = val.GetString();
                            break;
                        case "author":
                            mediaObject.Author = val.GetString();
                            break;
                        case "datecreated":
                            mediaObject.DateCreated = val.GetString();
                            break;
                        case "description":
                            mediaObject.Description = val.GetString();
                            break;
                        case "filenumber":
                            mediaObject.FileNumber = (int)val.GetNumber();
                            break;
                        case "googlezoom":
                            mediaObject.GoogleZoom = (int)val.GetNumber();
                            break;
                        case "gps":
                            mediaObject.GPS = val.GetString();
                            break;
                        case "height":
                            mediaObject.Height = (int)val.GetNumber();
                            break;
                        case "image":
                            mediaObject.SetLargeImage(val.GetString());

                            if (typeId == Constants.ITEM_TYPE_DIGITAL)
                                mediaObject.SetTileImage(val.GetString(), Constants.SRC_LOCATION_PHOTO);
                            else
                                mediaObject.SetTileImage(val.GetString(), Constants.SRC_LOCATION_VIDEO);

                            break;
                        case "key":
                            mediaObject.Id = (int)val.GetNumber();
                            mediaObject.DirectLink = Constants.DIRECTLINKBASE + mediaObject.Id.ToString();
                            break;
                        case "keywords":
                            mediaObject.Keywords = val.GetString();
                            AddKeywordsToSuggestionList(mediaObject.Keywords);
                            break;
                        case "latitude":
                            mediaObject.Latitude = val.GetNumber();
                            break;
                        case "location":
                            mediaObject.Location = val.GetString();
                            break;
                        case "longitude":
                            mediaObject.Longitude = val.GetNumber();
                            break;
                        case "title":
                            mediaObject.Title = val.GetString();
                            break;
                        case "rating":
                            mediaObject.Rating = val.GetString();
                            break;
                        case "videolength":
                            mediaObject.VideoLength = val.GetString();
                            break;
                        case "videoformat":
                            mediaObject.VideoFormat = val.GetString();
                            break;
                        case "group":
                            // Get the group of this MediaItem
                            var mediaObjectGroup = val.GetObject();

                            // Get the key from the group of this media item
                            IJsonValue groupKey;
                            if (!mediaObjectGroup.TryGetValue("CollectionId", out groupKey))
                                continue;

                            mediaObject.Group = _mediaObjectDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(((int)groupKey.GetNumber()).ToString()));

                            break;
                    }
                }
                
                // Determine Unique ID
                Tools.CreateUniqueIdCombination(mediaObject);

                bool isInCollection = false;
                foreach (var existingItem in _mediaObjectDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(mediaObject.Group.UniqueId)).Items) 
                {
                    if (existingItem.UniqueId.Equals(mediaObject.UniqueId))
                    {
                        isInCollection = true;
                        break;
                    }
                }

                if (!isInCollection)
                {
                    // Determine GPS string
                    Tools.DetermineGPS(mediaObject);

                    mediaObject.TypeId = typeId;
                    _mediaObjectDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(mediaObject.Group.UniqueId)).Items.Add(mediaObject);
                }
            }
        }

        private static void CreateMediaObjectsAndMediaObjectGroups(JsonArray mediaObjectArray, JsonArray groupsArray, int typeId)
        {
            CreateMediaObjectsAndMediaObjectGroups(mediaObjectArray, groupsArray, null, typeId);
        }

        private static void CreateMediaObjectsAndMediaObjectGroups(JsonArray mediaObjectArray, JsonArray groupsArray, JsonArray newMediaObjectArray, int typeId)
        {
            // Only add New Media Today when present
            if ((newMediaObjectArray != null) && (newMediaObjectArray.Count() > 0))
            {
                MediaObjectDataGroup mediaObjectGroup = new MediaObjectDataGroup(
                    Constants.NEWCOLLECTIONID,
                    Constants.NEWCOLLECTIONNAME,
                    Constants.NEWCOLLECTIONIMAGEPATH,
                    Constants.NEWCOLLECTIONDESCRIPTION,
                    newMediaObjectArray.Count());

                _mediaObjectDataSource.AllGroups.Add(mediaObjectGroup);
            }

            foreach (var item in groupsArray)
            {
                var obj = item.GetObject();

                String uniqueId = "";
                String title = "";
                String themeImagePath = "";
                String description = "";
                int mediaObjectsCount = 0;
                
                Uri _baseUri = new Uri("ms-appx:///");

                foreach (var key in obj.Keys)
                {
                    IJsonValue val;
                    if (!obj.TryGetValue(key, out val))
                        continue;

                    if (val.ValueType == JsonValueType.Null)
                        continue;

                    switch (key)
                    {
                        case "CollectionId":
                            uniqueId = val.GetNumber().ToString();
                            break;
                        case "CollectionName":
                            title = val.GetString();
                            break;
                        case "CollectionDescription":
                            description = val.GetString();
                            break;
                        case "CollectionCount":
                            mediaObjectsCount = (int)val.GetNumber();
                            break;
                        case "CollectionImage":
                            themeImagePath = "ms-appx:///Images/" + uniqueId.ToString() + ".jpg";
                            break;
                    }
                }

                MediaObjectDataGroup mediaObjectGroup = new MediaObjectDataGroup(uniqueId, title, themeImagePath, description, mediaObjectsCount);

                _mediaObjectDataSource.AllGroups.Add(mediaObjectGroup);
            }

            AddMediaToMasterList(mediaObjectArray, typeId, false);

            // Only add New Media Today when present
            if ((newMediaObjectArray != null) && (newMediaObjectArray.Count() > 0))
                AddMediaToMasterList(newMediaObjectArray, typeId, true);
        }

        private static void AddMediaToMasterList(JsonArray mediaObjectArray, int typeId, bool newMedia)
        {
            foreach (var item in mediaObjectArray)
            {
                var obj = item.GetObject();
                MediaObjectDataItem mediaObject = new MediaObjectDataItem();
                foreach (var key in obj.Keys)
                {
                    IJsonValue val;
                    if (!obj.TryGetValue(key, out val))
                        continue;

                    if (val.ValueType == JsonValueType.Null)
                        continue;

                    switch (key)
                    {
                        case "alttitle":
                            mediaObject.AltTitle = val.GetString();
                            break;
                        case "author":
                            mediaObject.Author = val.GetString();
                            break;
                        case "datecreated":
                            mediaObject.DateCreated = val.GetString();
                            break;
                        case "description":
                            mediaObject.Description = val.GetString();
                            break;
                        case "filenumber":
                            mediaObject.FileNumber = (int)val.GetNumber();
                            break;
                        case "googlezoom":
                            mediaObject.GoogleZoom = (int)val.GetNumber();
                            break;
                        case "height":
                            mediaObject.Height = (int)val.GetNumber();
                            break;
                        case "gps":
                            mediaObject.GPS = val.GetString();
                            break;
                        case "image":
                            mediaObject.SetLargeImage(val.GetString());

                            if (typeId == Constants.ITEM_TYPE_DIGITAL)
                                mediaObject.SetTileImage(val.GetString(), Constants.SRC_LOCATION_PHOTO);
                            else
                                mediaObject.SetTileImage(val.GetString(), Constants.SRC_LOCATION_VIDEO);

                            break;
                        case "key":
                            mediaObject.Id = (int)val.GetNumber();
                            mediaObject.DirectLink = Constants.DIRECTLINKBASE + mediaObject.Id.ToString();
                            break;
                        case "keywords":
                            mediaObject.Keywords = val.GetString();
                            AddKeywordsToSuggestionList(mediaObject.Keywords);
                            break;
                        case "latitude":
                            mediaObject.Latitude = val.GetNumber();
                            break;
                        case "location":
                            mediaObject.Location = val.GetString();
                            break;
                        case "longitude":
                            mediaObject.Longitude = val.GetNumber();
                            break;
                        case "title":
                            mediaObject.Title = val.GetString();
                            break;
                        case "rating":
                            mediaObject.Rating = val.GetString();
                            break;
                        case "videolength":
                            mediaObject.VideoLength = val.GetString();
                            break;
                        case "videoformat":
                            mediaObject.VideoFormat = val.GetString();
                            break;
                        case "group":
                            // Get the group of this MediaItem
                            var mediaObjectGroup = val.GetObject();

                            // Get the key from the group of this media item
                            IJsonValue groupKey;
                            if (!mediaObjectGroup.TryGetValue("CollectionId", out groupKey))
                                continue;

                            if (newMedia)
                                mediaObject.Group = _mediaObjectDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(Constants.NEWCOLLECTIONID));
                            else
                                mediaObject.Group = _mediaObjectDataSource.AllGroups.FirstOrDefault(c => c.UniqueId.Equals(((int)groupKey.GetNumber()).ToString()));

                            break;
                    }
                }
                // All fields have been processed

                // Determine GPS
                Tools.DetermineGPS(mediaObject);

                // Determine Unique ID
                Tools.CreateUniqueIdCombination(mediaObject);
                
                // Check if items has not already been added
                if (mediaObject.Group.Items.FirstOrDefault(m => m.UniqueId.Equals(mediaObject.UniqueId)) == null)
                {
                    mediaObject.TypeId = typeId;
                    // select the group and add this item to the items in this group
                    mediaObject.Group.Items.Add(mediaObject);
                }
            }
        }
    }
}